//
//  vdKernel.m
//  Void Dead
//
//  Created by Sidney Just on 16.11.09.
//
//  Copyright © 2009 by Sidney Just
//  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated 
//  documentation files (the "Software"), to deal in the Software without restriction, including without limitation 
//  the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, 
//  and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
//  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
//  INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
//  PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE 
//  FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
//  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

#import "vdKernel.h"
#import "vdNode.h"
#import "vdMisc.h"
#import "matrix.h"

#import "vdMacros.h"

const char *cVersion = "Void Dead 0.4.2";

void initEnabler();
void releaseEnabler();

void setAtctiveRenderTarget(vdRenderTarget *target);

vdRenderingAPI renderingAPI;
vdView *renderingView;
vdRenderTarget *lastTarget;
vdTexNode *tex;

@implementation vdKernel
@synthesize deltaTime;
@synthesize orientation, renderView;
@synthesize tick, fps;
@synthesize rAPI, engineCaps, version, useDisplayLink;

#pragma mark -
#pragma mark Conversion

- (CGPoint)convertUIToOpenGL:(CGPoint)convertPoint {
	if(renderView)
	{
		switch(orientation) {
			case UIInterfaceOrientationPortrait:
				return CGPointMake(convertPoint.x, convertPoint.y);
				break;
				
			case UIInterfaceOrientationPortraitUpsideDown:
				return CGPointMake(-convertPoint.x, -convertPoint.y);
				break;
				
			case UIInterfaceOrientationLandscapeLeft:
				return CGPointMake(renderView.backingHeight-convertPoint.y, convertPoint.x);
				break;
				
			case UIInterfaceOrientationLandscapeRight:
				return CGPointMake(convertPoint.y, renderView.backingWidth-convertPoint.x);
				break;
		}
	}
	
	return CGPointMake(0, 0);;
}

- (CGPoint)convertOpenGLToUI:(CGPoint)convertPoint {
	CGPoint returnPoint = CGPointMake(0, 0);
	
	if(renderView)
	{
		switch(orientation) {
			case UIInterfaceOrientationPortrait:
				returnPoint = CGPointMake(convertPoint.x, convertPoint.y);
				break;
				
			case UIInterfaceOrientationPortraitUpsideDown:
				returnPoint = CGPointMake(renderView.backingWidth - (-convertPoint.x), renderView.backingHeight - (-convertPoint.y));
				break;
				
			case UIInterfaceOrientationLandscapeLeft:
				returnPoint = CGPointMake(renderView.backingHeight - (-convertPoint.x), convertPoint.y);
				break;
				
			case UIInterfaceOrientationLandscapeRight:
				returnPoint = CGPointMake(convertPoint.x, renderView.backingWidth - (-convertPoint.y));
				break;
		}
	}
	
	return returnPoint;
}


- (CGPoint)applyOrientation:(CGPoint)convertPoint {
	CGPoint returnPoint = CGPointMake(0, 0);
	
	if(renderView)
	{
		switch(orientation) {
			case UIInterfaceOrientationPortrait:
				returnPoint = CGPointMake(convertPoint.x, convertPoint.y);
				break;
				
			case UIInterfaceOrientationPortraitUpsideDown:
				returnPoint = CGPointMake(-convertPoint.x, -convertPoint.y);
				break;
				
			case UIInterfaceOrientationLandscapeLeft:
				returnPoint = CGPointMake(-convertPoint.y, convertPoint.x);
				break;
				
			case UIInterfaceOrientationLandscapeRight:
				returnPoint = CGPointMake(convertPoint.y, -convertPoint.x);
				break;
		}
	}
	
	return returnPoint;
}

#pragma mark -
#pragma mark Erros

- (void)getOpenGLErrors {
#ifdef VD_DEBUG
	GLenum lastError = glGetError();
	
	if(lastError == GL_NO_ERROR)
		return;
	
	vdErrorMessage message;
	message.event = vdOpenGLError;
	message.glError = lastError;
	
	[handler fireEvent:vdErrorEvent sender:self data:&message];
	
	[self getOpenGLErrors];
#endif
}

#pragma mark -
#pragma mark Misc

- (void)setOrientation:(UIInterfaceOrientation)newOrientation {
	if(renderView)
	{
		renderView.orientation = newOrientation;
		orientation = newOrientation;
		[[UIApplication sharedApplication] setStatusBarOrientation:orientation animated:NO];
	}
}

- (void)updateToOrientation {
	[self setOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
}

- (CGRect)viewDimension {
	if(!renderView)
		return CGRectMake(0, 0, 0, 0);
	
	switch(orientation) {
		case UIInterfaceOrientationPortrait:
			return CGRectMake(0, 0, renderView.backingWidth, renderView.backingHeight);
			break;
		case UIInterfaceOrientationPortraitUpsideDown:
			return CGRectMake(0, 0, renderView.backingWidth, renderView.backingHeight);
			break;
		case UIInterfaceOrientationLandscapeLeft:
			return CGRectMake(0, 0, renderView.backingHeight, renderView.backingWidth);
			break;
		case UIInterfaceOrientationLandscapeRight:
			return CGRectMake(0, 0, renderView.backingHeight, renderView.backingWidth);
			break;
	}  
	
	return CGRectMake(0, 0, 0, 0);
}

- (void)setRootNode:(vdNode *)aNode {
	renderNode = aNode;
	if(renderNode)
	{
		renderNode.mother = renderView;
		renderNode.father = self;
		renderNode.parent = NULL;
	}
}

- (vdNode *)getRootNode {
	return renderNode;
}

- (void)attachToWindow:(UIWindow *)aWindow {
	[renderView removeFromSuperview];
	
	if(aWindow)
		[aWindow addSubview:renderView];
}

- (void)attachToView:(UIView *)aView {
	[renderView removeFromSuperview];
	
	if(aView)
		[aView addSubview:renderView];
}

- (void)attachViewToWindow:(UIWindow *)aWindow {
	[self attachToWindow:aWindow];
}

- (void)attachViewToView:(UIView *)aView {
	[self attachToView:aView];
}

- (void)resizeRenderView:(CGRect)frame {
	if(renderView)
	{
		[renderView setFrame:frame];
	}
}

- (void)writeDeltaTimeInto:(NSTimeInterval *)delta {
	userDelta = delta;
}

#pragma mark -
#pragma mark Post Processing

- (void)addShader:(vdShader *)shader intoRenderTarget:(vdRenderTarget *)target {
	target->postShaders += 1;
	target->postShader  = (vdShader **)realloc(target->postShader, target->postShaders*sizeof(vdShader *));
	target->postShader[target->postShaders-1] = shader;
}

- (void)removeShader:(vdShader *)shader fromRenderTarget:(vdRenderTarget *)target {
	for(int i=0; i<target->postShaders; i++)
	{
		if(target->postShader[i] == shader)
		{
			for(int j=i; j<target->postShaders-1; j++)
			{
				target->postShader[j] = target->postShader[j+1];
			}
			
			target->postShaders -= 1;
			target->postShader  = (vdShader **)realloc(target->postShader, target->postShaders*sizeof(vdShader *));
		}
	}
}

- (vdRenderTarget *)createRenderTarget {
	renderTargets += 1;
	renderTarget = (vdRenderTarget **)realloc(renderTarget, renderTargets*sizeof(vdRenderTarget *));
	renderTarget[renderTargets-1] = (vdRenderTarget *)malloc(sizeof(vdRenderTarget));
	renderTarget[renderTargets-1]->postShaders = 0;
	renderTarget[renderTargets-1]->postShader = (vdShader **)malloc(sizeof(vdShader *));
	renderTarget[renderTargets-1]->clearBuffer = YES;
	
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if(rAPI == OpenGLESAPI2)
	{
		glGenFramebuffers(1, &renderTarget[renderTargets-1]->Framebuffer);
		glBindFramebuffer(GL_FRAMEBUFFER, renderTarget[renderTargets-1]->Framebuffer);
	} else {
		glGenFramebuffersOES(1, &renderTarget[renderTargets-1]->Framebuffer);
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, renderTarget[renderTargets-1]->Framebuffer);
	}
#else
	glGenFramebuffersOES(1, &renderTarget[renderTargets-1]->Framebuffer);
	glBindFramebufferOES(GL_FRAMEBUFFER_OES, renderTarget[renderTargets-1]->Framebuffer);
#endif
	
	glGenTextures(1, &renderTarget[renderTargets-1]->Texture);
	glBindTexture(GL_TEXTURE_2D, renderTarget[renderTargets-1]->Texture);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,  512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	
	
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	if(rAPI == OpenGLESAPI2)
	{
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTarget[renderTargets-1]->Texture, 0);
	} else {
		glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, renderTarget[renderTargets-1]->Texture, 0);
	}
#else
	glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, renderTarget[renderTargets-1]->Texture, 0);
#endif
	[renderView bindFramebuffer];
	
	return renderTarget[renderTargets-1];
}


- (void)deleteRenderTarget:(vdRenderTarget *)target {
	for(int i=0; i<renderTargets; i++)
	{
		if(renderTarget[i] == target)
		{
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
			if(rAPI == OpenGLESAPI2)
			{
				glDeleteFramebuffers(1, &target->Framebuffer);
				glDeleteTextures(1, &target->Texture);
			} else {
				glDeleteFramebuffersOES(1, &target->Framebuffer);
				glDeleteTextures(1, &target->Texture);
			}
#else
			glDeleteFramebuffersOES(1, &target->Framebuffer);
			glDeleteTextures(1, &target->Texture);
#endif
			
			free(target->postShader);
			free(target);
			
			for(int j=i; j<renderTargets-1; j++)
			{
				renderTarget[j] = renderTarget[j+1];
			}
			
			renderTargets -= 1;
			renderTarget = (vdRenderTarget **)realloc(renderTarget, renderTargets*sizeof(vdRenderTarget *));
			
			return;
		}
	}
}

#pragma mark -
#pragma mark Blocks

#if defined(USE_OS_32) || defined(USE_OS_40)

- (vd_queue *)createQueue:(vd_block)block withTime:(int)timeStep {
	vd_queue *queue = (vd_queue *)malloc(sizeof(vd_queue));
	
	queue->block		= block;
	queue->timeStep	= timeStep;
	
	Block_copy(queue->block); // Copys the block to the heap
	
	return queue;
}

- (void)deleteQueue:(vd_queue *)queue {
	Block_release(queue->block); // releases the block
	free(queue);
}

- (void)dispatchQueue:(vd_queue *)queue autoDelete:(BOOL)yesOrNo {
	listLength += 1;
	
	dispatchList = (vd_dispatch *)realloc(dispatchList, listLength*sizeof(vd_dispatch));
	dispatchList[listLength-1].queue = queue;
	dispatchList[listLength-1].timeLeft = queue->timeStep;
	dispatchList[listLength-1].autoDelete = yesOrNo;
}


- (void)fireBlocks {
	for(int i=0; i<listLength; i++)
	{
		dispatchList[i].timeLeft -= 1;
		
		if(dispatchList[i].timeLeft <= 0)
		{
			dispatchList[i].queue->block();
			if(dispatchList[i].autoDelete)
				[self deleteQueue:dispatchList[i].queue];
			
			for(int j=i; j<listLength-1; i++)
			{
				dispatchList[j] = dispatchList[j+1];
			}
			
			listLength -= 1;
			dispatchList = (vd_dispatch *)realloc(dispatchList, listLength*sizeof(vd_dispatch));
			
			i -= 1;
		}
	}
}

#endif

#pragma mark -
#pragma mark Rendering

- (void)drawScene {	
	// Event
	vdEngineMessage event;
	
	event.event = vdEngineFrameWillBegin;
	[handler fireEvent:vdEngineEvent sender:self data:&event];
	
	// Prepare the rendering
	[renderView prepareRendering];
	[[vdRenderer sharedRenderer] setFocus];
	lastTarget = NULL;
	
	event.event = vdEngineFrameDidBegin;
	[handler fireEvent:vdEngineEvent sender:self data:&event];
	
#if defined(USE_OS_32) || defined(USE_OS_40)
	[self fireBlocks];
#endif
	
	// Rendering
	if(renderNode)
		[renderNode contact:CGPointMake(0, 0) :deltaTime];
	
	event.event = vdEngineFrameWillEnd;
	[handler fireEvent:vdEngineEvent sender:self data:&event];
	
	[[vdRenderer sharedRenderer] finalizeScene];
	setAtctiveRenderTarget(NULL);
	[renderView completeRendering]; // Swap the buffers
	
	[self getOpenGLErrors];
	
	// Delta Time
	static NSTimeInterval lastDrawTime;
	if(lastDrawTime)
		deltaTime = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;

	lastDrawTime = [NSDate timeIntervalSinceReferenceDate];
	
	if(userDelta)
		*userDelta = deltaTime;
	
	renderView.deltaTime = deltaTime;
	fps = (int)(1/deltaTime);
	
	tick++;
	
	// Event
	event.event = vdEngineFrameDidEnd;
	[handler fireEvent:vdEngineEvent sender:self data:&event];
}

- (void)clearScreen {
	[renderView prepareRendering];
	[renderView completeRendering];
}

- (void)startRendering {	
	fps = 0;
	deltaTime = 0;
	
	if((!(engineCaps & vdCapsDisplayLink)) || (!useDisplayLink))
	{
		if(renderTimer)
			return;
		
		renderTimer = [NSTimer scheduledTimerWithTimeInterval:1/maxFPS target:self selector:@selector(drawScene) userInfo:nil repeats:YES];
	} else {
		if(displayLink)
			return;
		
		displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(drawScene)];
		[displayLink setFrameInterval:floor((1.0f/maxFPS)*60.0f)];
		[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
	}

}

- (void)stopRendering {
	if(renderTimer)
	{
		[renderTimer invalidate];
		renderTimer = NULL;
	}
	
	if(displayLink)
	{
		[displayLink invalidate];
		displayLink = NULL;
	}
}

- (BOOL)isRendering {
	if(renderTimer || displayLink)
	{
		return YES;
	}
	
	return NO;
}

- (void)setMaxFPS:(int)FPS {
	maxFPS = (float)FPS;
	
	if(renderTimer || displayLink)
	{
		[self stopRendering];
		[self startRendering];
	}
}

- (void)setUseDisplayLink:(BOOL)_yesNo {
	if(useDisplayLink != _yesNo)
	{
		useDisplayLink = _yesNo;
		
		if(renderTimer || displayLink)
		{
			[self stopRendering];
			[self startRendering];
		}
	}
}

#pragma mark -
#pragma mark Misc

- (NSString *)getOpenGLVersion {
	return oglVersion;
}

- (BOOL)createRenderingView:(vdRenderingAPI)kApi {
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
	vdView *temp = [[vdES2 alloc] initWithFrame:CGRectMake(0, 0, 32, 32)];
	if(temp)
	{
		engineCaps |= vdCapsTexture2048;
	} else {
		engineCaps |= vdCapsTexture1024;
	}
	[temp release];
#else
	engineCaps |= vdCapsTexture1024;
#endif
	
	if(kApi == OpenGLESAPI1)
	{
		renderView = [[vdES1 alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
		if(!renderView)
		{
			vdErrorMessage message;
			message.event = vdEngineError;
			message.vdError = vdFallback;
			
			[[vdEventHandler sharedEventHandler] fireEvent:vdErrorEvent sender:self data:&message];
			
			vdLog(@"Failed to create OpenGL ES view, can't fallback");
			
			return NO;
		}
		rAPI = OpenGLESAPI1;
	} 
	else if(kApi == OpenGLESAPI2)
	{
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
		rAPI = OpenGLESAPI2;
		renderView = [[vdES2 alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
		if(!renderView)
		{ // Fallback
			vdErrorMessage message;
			message.event = vdEngineError;
			message.vdError = vdFallback;
			
			[[vdEventHandler sharedEventHandler] fireEvent:vdErrorEvent sender:self data:&message];
			
			vdLog(@"Failed to create OpenGL ES view, Fallback to OpenGLES 1");
			
			rAPI = OpenGLESAPI1;
			renderView = [[vdES1 alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
			if(!renderView)
			{
				vdErrorMessage message;
				message.event = vdEngineError;
				message.vdError = vdFallback;
				
				[[vdEventHandler sharedEventHandler] fireEvent:vdErrorEvent sender:self data:&message];
				
				vdLog(@"Failed to create OpenGL ES view, can't fallback");
				
				return NO;
			}
		}
#else
		rAPI = OpenGLESAPI1;
		renderView = [[vdES1 alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
		if(!renderView)
		{
			vdErrorMessage message;
			message.event = vdEngineError;
			message.vdError = vdFallback;
			
			[[vdEventHandler sharedEventHandler] fireEvent:vdErrorEvent sender:self data:&message];
			
			vdLog(@"Failed to create OpenGL ES view, can't fallback");
			
			return NO;
		}
		
#endif
	}
	
	renderView.opaque = YES;
	oglVersion = [[NSString alloc] initWithFormat:@"%s", glGetString(GL_VERSION)];
	[self setOrientation:[[UIApplication sharedApplication] statusBarOrientation]];
	
	return YES;
}

#pragma mark -
#pragma mark Con- Destructor

static vdKernel *_sharedKernel = NULL;

+ (vdKernel *)sharedKernel {
	if(!_sharedKernel)
	{
		vdKernel *temp = [[vdKernel alloc] initWithAPI:OpenGLESAPI2];
		_sharedKernel = temp;
	}
	return _sharedKernel;
}

+ (BOOL)createSharedKernelWithAPI:(vdRenderingAPI)kApi {
	if(!_sharedKernel)
	{
		vdKernel *temp = [[vdKernel alloc] initWithAPI:kApi];
		_sharedKernel = temp;
		return YES;
	}
	return NO;
}

- (id)initWithAPI:(vdRenderingAPI)kApi {
	if(_sharedKernel)
	{
		[self release];
		return _sharedKernel;
	}
	
	if(self = [super init])
	{
		version = [[NSString alloc] initWithFormat:@"%s", cVersion];
		
		engineCaps = 0;
		
		_sharedKernel = self;
		
		maxFPS = 60;
		renderTimer = NULL;
		displayLink = NULL;
		
		useDisplayLink = YES;
		
		tick = 0;
		
		renderView = NULL;
		
		vdLog(@"%@", version);
		vdLog(@"Creating kernel %@ with OpenGL ES %i", _sharedKernel, (int)kApi);
		
		if(![self createRenderingView:kApi])
		{
			[self release];
			return NULL;
		}
		
		renderNode = NULL;
		userDelta = NULL;
		
		[vdShaderLib sharedLib];
		[vdRenderer sharedRenderer];
		handler = [vdEventHandler sharedEventHandler];
		
		if(rAPI == OpenGLESAPI2)
		{
			engineCaps |= vdCapsShader;
		}
		
		if([[[UIDevice currentDevice] systemVersion] compare:@"3.1" options:NSNumericSearch] != NSOrderedAscending)
		{
			engineCaps |= vdCapsDisplayLink;
		}

		renderingAPI = rAPI;
		renderingView = renderView;
		
		[[vdRenderer sharedRenderer] setFocus];
		
		renderTargets = 0;
		renderTarget = (vdRenderTarget **)malloc(sizeof(vdRenderTarget *));
		
		tex = [[vdTexNode alloc] init];
		
#if defined(USE_OS_32) || defined(USE_OS_40)
		dispatchList = (vd_dispatch *)malloc(sizeof(vd_dispatch));
		listLength = 0;
#endif
		
		initEnabler();
	}
	return self;
}

- (void)destroy {
	[self stopRendering];
	
	int i = [self retainCount];
	
	for(int j=0; j<i; j++)
		[self release];
}

- (void)dealloc {
	if(renderNode)
		[renderNode destroy];
	
	[version release];
	
	int j = [renderView retainCount];
	for(int i=0; i<j; i++)
		[renderView release];
	
	[oglVersion release];
	
	[[vdTexManager sharedManager] release];
	[[vdRenderer sharedRenderer] release];
	[[vdShaderLib sharedLib] release];
	[[vdEventHandler sharedEventHandler] release];
	
	releaseEnabler();
	
	for(int i=0; i<renderTargets; i++)
	{
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
		if(rAPI == OpenGLESAPI2)
		{
			glDeleteFramebuffers(1, &renderTarget[i]->Framebuffer);
			glDeleteTextures(1, &renderTarget[i]->Texture);
		} else {
			glDeleteFramebuffersOES(1, &renderTarget[i]->Framebuffer);
			glDeleteTextures(1, &renderTarget[i]->Texture);
		}
#else
		glDeleteFramebuffersOES(1, &renderTarget[i]->Framebuffer);
		glDeleteTextures(1, &renderTarget[i]->Texture);
#endif
		
		free(renderTarget[i]->postShader);
		free(renderTarget[i]);
	}
	
	free(renderTarget);
	[tex release];
	
#if defined(USE_OS_32) || defined(USE_OS_40)
	free(dispatchList);
#endif
	
	vdLog(@"Destroyed %@", self);
	
	if(self == _sharedKernel)
		_sharedKernel = NULL;
	
	[super dealloc];
}

@end


GLint oldFramebuffer;

void setAtctiveRenderTarget(vdRenderTarget *target)
{
	if(renderingAPI == OpenGLESAPI1)
	{
		return;
	}
	
	if(lastTarget)
	{
		if(lastTarget == target)
		{
			return;
		}
		
		tex.texture = lastTarget->Texture;
		
		GLfloat vertices[12];
		GLfloat texCoords[12];
		
		texCoords[0] = 1; 
		texCoords[1] = 1;
		
		texCoords[2] = 0;
		texCoords[3] = 1;
		
		texCoords[4] = 0; 
		texCoords[5] = 0;
		
		texCoords[6] = 1; 
		texCoords[7] = 0;
		
		texCoords[8] = 1; 
		texCoords[9] = 1;
		
		texCoords[10] = 0; 
		texCoords[11] = 0;
		//----------------
		
		vertices[0] = 512; 
		vertices[1] = 512;
		
		vertices[2] = 0;
		vertices[3] = 512;
		
		vertices[4] = 0; 
		vertices[5] = 0;
		
		vertices[6] = 512; 
		vertices[7] = 0;
		
		vertices[8] = 512; 
		vertices[9] = 512;
		
		vertices[10] = 0; 
		vertices[11] = 0;
		
		vdColor color;
		color.red = 1.0f;
		color.green = 1.0f;
		color.blue = 1.0f;
		color.alpha = 1.0f;
		
		[[vdRenderer sharedRenderer] flushContent];
		
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
		if(renderingAPI == OpenGLESAPI2)
		{
			for(int i=0; i<lastTarget->postShaders; i++)
			{
				
				if(i == lastTarget->postShaders-1)
				{
					if(renderingView.viewFramebuffer != oldFramebuffer)
					{
						glBindFramebuffer(GL_FRAMEBUFFER, oldFramebuffer);
					} else {
						[renderingView bindFramebuffer];
					}
				}
				
				lastTarget->postShader[i].texture = tex;
				lastTarget->postShader[i].vertices = vertices;
				lastTarget->postShader[i].texCoords = texCoords;
				lastTarget->postShader[i].color = &color;
				lastTarget->postShader[i].positionsPerVertex = 2;
				lastTarget->postShader[i].isPostProcessingShader = YES;
				
				glUseProgram(lastTarget->postShader[i].shader);
				[lastTarget->postShader[i] runShader];
				
				glDrawArrays(GL_TRIANGLES, 0, 6);
			}
		}
#endif
	}
	
	if(target)
	{
#if defined(USE_OS_30) || defined(USE_OS_32) || defined(USE_OS_40) || USE_OS_32 || USE_OS_40
		if(renderingAPI == OpenGLESAPI2)
		{
			glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFramebuffer);
		}

		if(renderingAPI == OpenGLESAPI2)
		{
			glBindFramebuffer(GL_FRAMEBUFFER, target->Framebuffer);

			if(target->clearBuffer)
			{
				glClear(GL_COLOR_BUFFER_BIT);
			}
#endif
		}
		
	}
	
	lastTarget = target;
}

